#include "Source/Sprite.h"
#include "Source/Texture.h"
#include "Source/Core/Vector.h"
#include "Source/Application.h"
#include <string>
#include <cassert>
#include <stdio.h>
#include "Source/Globals.h"
#include "Source/IO/File.h"
#include "Source/utils.h"
#include <boost/lexical_cast.hpp>
#include "json.h"

Sprite::Sprite():
m_sFilename(""),
m_sTexture(""),
m_nCurrentFrame(0),
m_nMaxFrames(0),
m_bTextureLoaded(false),
m_bIsVisible(true),
m_bIsInAnimation(false),
m_nWidth(0),
m_nHeight(0)
{
	printf("Creating sprite...");
	m_position.x = 0;
	m_position.y = 0;
	m_position.z = 0;
	m_sourceRect.x = 0;
	m_sourceRect.y = 0;
	m_sourceRect.w = 0; 
	m_sourceRect.h = 0;
}

Sprite::~Sprite() 
{
	UnloadTexture();
}

void Sprite::SetPosition(const Vector newPosition)     // Position
{
	m_position = newPosition;
}

Vector Sprite::GetPosition() const // Position
{
	return m_position;
}

void Sprite::SetCurrentFrame(const int newFrame) // Current Frame
{
	m_nCurrentFrame = newFrame;
}

int Sprite::GetCurrentFrame() const// Current Frame
{
	return m_nCurrentFrame;
}

void Sprite::SetMaxFrames(const int newMaxFrames) // Max Frames
{
	m_nMaxFrames = newMaxFrames;
}

int Sprite::GetMaxFrames() const // Current Frame
{
	return m_nMaxFrames;
}

const std::string Sprite::GetFilename() const 
{
	return m_sFilename;
}

void Sprite::LoadTexture(std::string filename) //TODO: Leave only Sprite file reading here and keep pointer to the texture from texture manager
{
	//Reading the json document contents and storing them in std::string
	m_sFilename = filename;
	CL_File* file = CL_File::Open(filename, E_FileModes_ReadText);
	
	std::string jsonDoc="";
	while(!file->IsEOF())
	{
		std::string line;
		file->ReadLine(line);
		jsonDoc.append(line);
	}

	file->Close();
	delete file;
	file=NULL;


	//Parse the document and initialize the sprite
	Json::Value data;
	Json::Reader reader;
	if(!reader.parse(jsonDoc, data, false))
	assert(false); //error parsing the Json

	m_position.x = (float)data["position_x"].asDouble(); // X coordinate
	m_position.y = (float)data["position_y"].asDouble(); // Y coordinate
	m_nMaxFrames = data["max_frames"].asInt(); // Max frames
	m_nWidth	 = data["width"].asInt(); // Width
	m_nHeight	 = data["height"].asInt(); // Height
	m_sTexture	 = data["filename"].asString(); // Height

	m_sourceRect.w = m_nWidth;
	m_sourceRect.h = m_nHeight;

	m_texture = new Texture(); //TODO: MOVE THIS TO TEXTURE MANAGER!!!
	m_texture->Load(m_sTexture);

	m_bTextureLoaded = true;
}

void Sprite::UnloadTexture()
{
	if(m_bTextureLoaded)
	{
		m_texture->Unload();
		delete m_texture;
		m_texture = NULL;
	}
	m_bTextureLoaded = false;
}

void Sprite::SaveTexture(std::string filename)
{
	CL_File* file = CL_File::Open(filename, E_FileModes_WriteText);
	
	Json::Value data;
	Json::StyledWriter writer;

	data["position_x"] = m_position.x;
	data["position_y"] = m_position.y;
	data["max_frames"] = m_nMaxFrames;
	data["width"] = m_nWidth;
	data["height"] = m_nHeight;
	data["filename"] = m_sTexture;

	file->WriteLine(writer.write(data));

	//std::vector<std::string> lines;

	//lines.push_back(boost::lexical_cast<std::string>(m_position.x)); // X coordinate
	//lines.push_back(boost::lexical_cast<std::string>(m_position.y)); // Y coordinate
	//lines.push_back(boost::lexical_cast<std::string>(m_nMaxFrames)); // Max frames
	//lines.push_back(boost::lexical_cast<std::string>(m_nWidth)); // Width
	//lines.push_back(boost::lexical_cast<std::string>(m_nHeight)); // Height
	//lines.push_back(m_sFilename); // Texture filename (TODO!!!!!! texture ID)

	//for(int i=0; i<lines.size()-1; i++)
	//{
	//	if(i!=lines[i].size()-1)
	//	lines[i].append(" (digit)");
	//	file->WriteLine(lines[i]);
	//}
	file->Close();
	delete file;
	file=NULL;
	//TODO: Texture saving
}

void Sprite::Draw()
{
	if(!m_bTextureLoaded || !m_bIsVisible)
	return;

	SDL_Rect dest;
	dest.x = m_position.x;
	dest.y = m_position.y;
	dest.w = m_nWidth;
	dest.h = m_nHeight;

	m_texture->Draw(&m_sourceRect, Application::getInstance()->GetScreen(), &dest);
}

void Sprite::Update()
{
	if(m_bIsInAnimation)
	{
		m_nCurrentFrame++;
		if(m_nCurrentFrame>m_nMaxFrames-1)	//-1 for the indeces starting at 0
		{
			m_nCurrentFrame = 0;
			m_bIsInAnimation = false;
		}
	}

	m_sourceRect.x = m_nCurrentFrame*m_nWidth;
	m_sourceRect.y = 0;
	m_sourceRect.w = m_nWidth;
	m_sourceRect.h = m_nHeight;
}

void Sprite::SetIsInAnimation(bool isInAnimation)
{
	m_bIsInAnimation = isInAnimation;
}

bool Sprite::GetIsInAnimation() const
{
	return m_bIsInAnimation;
}
	
const int Sprite::GetWidth() const
{
	if(m_bTextureLoaded)
		return m_texture->GetTexture()->w;
	else
		return 0;
}

const int Sprite::GetHeight() const
{
	if(m_bTextureLoaded)
		return m_texture->GetTexture()->h;
	else
		return 0;
}